## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.1 ✔ tibble 3.2.1
## ✔ lubridate 1.9.4 ✔ tidyr 1.3.1
## ✔ purrr 1.0.4
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
## Loading required package: carData
##
## Attaching package: 'car'
##
## The following object is masked from 'package:dplyr':
##
## recode
##
## The following object is masked from 'package:purrr':
##
## some
##
## Attaching package: 'scales'
##
## The following object is masked from 'package:purrr':
##
## discard
##
## The following object is masked from 'package:readr':
##
## col_factor
##
## Attaching package: 'kableExtra'
##
## The following object is masked from 'package:dplyr':
##
## group_rows
## Rows: 49244 Columns: 35
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (9): TaskID, ActionID, distance, direction, complexity, zoomDirection,...
## dbl (22): UserID, main_translation_x, main_translation_y, main_translation_...
## lgl (3): rotateGlobeWhileDragging, oneHandedRotationGesture, moveGlobeWhil...
## dttm (1): Date
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 12 Columns: 8
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (7): Timestamp, Academic_level, Gender, Age_group, Exp_ARVR, Globe_usage...
## dbl (1): UserID
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 12 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): Timestamp, Mentally_demanding, Physically_demanding
## dbl (1): UserID
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 12 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): Timestamp, Mentally_demanding, Physically_demanding
## dbl (1): UserID
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 12 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): Timestamp, Positioning_preference, Positioning_feedback
## dbl (1): UserID
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 12 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): Timestamp, Mentally_demanding, Physically_demanding
## dbl (1): UserID
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 12 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): Timestamp, Mentally_demanding, Physically_demanding
## dbl (1): UserID
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 12 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): Timestamp, Rotation_preference, Rotation_feedback
## dbl (1): UserID
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 12 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): Timestamp, Mentally_demanding, Physically_demanding
## dbl (1): UserID
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 12 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): Timestamp, Mentally_demanding, Physically_demanding
## dbl (1): UserID
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 12 Columns: 4
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (3): Timestamp, Scale_preference, Scale_feedback
## dbl (1): UserID
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## Rows: 12 Columns: 6
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (5): Timestamp, Combined_positioning_preference, Combined_rotation_prefe...
## dbl (1): UserID
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
## UserID TaskID ActionID
## Min. : 1.000 Length:49244 Length:49244
## 1st Qu.: 4.000 Class :character Class :character
## Median : 7.000 Mode :character Mode :character
## Mean : 6.741
## 3rd Qu.:10.000
## Max. :12.000
## rotateGlobeWhileDragging oneHandedRotationGesture moveGlobeWhileScaling
## Mode :logical Mode :logical Mode :logical
## FALSE:36803 FALSE:11933 FALSE:46552
## TRUE :12441 TRUE :37311 TRUE :2692
##
##
##
## distance direction complexity zoomDirection
## Length:49244 Length:49244 Length:49244 Length:49244
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
##
##
##
## Date Type ActionStatus
## Min. :2025-04-23 05:27:13.00 Length:49244 Length:49244
## 1st Qu.:2025-04-25 01:36:58.00 Class :character Class :character
## Median :2025-04-26 00:45:01.00 Mode :character Mode :character
## Mean :2025-04-27 21:46:53.98
## 3rd Qu.:2025-05-01 07:26:51.00
## Max. :2025-05-05 23:37:33.00
## main_translation_x main_translation_y main_translation_z main_rotation_x
## Min. :-7.099065 Min. :-0.3298 Min. :-3.487 Min. :-0.97540
## 1st Qu.:-0.400000 1st Qu.: 0.9000 1st Qu.:-1.921 1st Qu.:-0.03161
## Median :-0.004060 Median : 0.9000 Median :-1.500 Median : 0.00000
## Mean :-0.005048 Mean : 1.2326 Mean :-1.683 Mean :-0.03896
## 3rd Qu.: 0.400000 3rd Qu.: 1.5539 3rd Qu.:-1.500 3rd Qu.: 0.00000
## Max. : 3.256168 Max. : 3.8304 Max. : 5.006 Max. : 0.97834
## main_rotation_y main_rotation_z main_rotation_w main_scale_x
## Min. :-1.0000 Min. :-0.97710 Min. :-0.9997261 Min. :0.08431
## 1st Qu.:-0.2033 1st Qu.: 0.00000 1st Qu.: 0.0000001 1st Qu.:0.99989
## Median : 0.9601 Median : 0.00000 Median : 0.0626987 Median :1.00000
## Mean : 0.5003 Mean : 0.01287 Mean : 0.2756917 Mean :0.99575
## 3rd Qu.: 1.0000 3rd Qu.: 0.00000 3rd Qu.: 0.6346812 3rd Qu.:1.00002
## Max. : 1.0000 Max. : 0.98922 Max. : 0.9999814 Max. :7.69231
## main_scale_y main_scale_z target_translation_x target_translation_y
## Min. :0.08431 Min. :0.08431 Min. :-3.10000 Min. :0.613
## 1st Qu.:0.99994 1st Qu.:0.99990 1st Qu.:-0.40000 1st Qu.:0.900
## Median :1.00000 Median :1.00000 Median : 0.00000 Median :0.900
## Mean :0.99577 Mean :0.99576 Mean :-0.02449 Mean :1.245
## 3rd Qu.:1.00002 3rd Qu.:1.00002 3rd Qu.: 0.40000 3rd Qu.:1.773
## Max. :7.69231 Max. :7.69231 Max. : 2.33777 Max. :2.547
## target_translation_z target_rotation_x target_rotation_y target_rotation_z
## Min. :-3.3210 Min. :-0.3928 Min. :-0.6935 Min. :-0.21194
## 1st Qu.:-1.9598 1st Qu.:-0.3584 1st Qu.:-0.5655 1st Qu.: 0.00000
## Median :-1.5000 Median : 0.0000 Median : 1.0000 Median : 0.00000
## Mean :-1.6971 Mean :-0.1153 Mean : 0.3768 Mean :-0.01644
## 3rd Qu.:-1.5000 3rd Qu.: 0.0000 3rd Qu.: 1.0000 3rd Qu.: 0.00000
## Max. :-0.8953 Max. : 0.0000 Max. : 1.0000 Max. : 0.13795
## target_rotation_w target_scale_x target_scale_y target_scale_z
## Min. :-0.9761015 Min. :0.1700 Min. :0.1700 Min. :0.1700
## 1st Qu.: 0.0000001 1st Qu.:1.0000 1st Qu.:1.0000 1st Qu.:1.0000
## Median : 0.0000001 Median :1.0000 Median :1.0000 Median :1.0000
## Mean : 0.2914215 Mean :0.9946 Mean :0.9946 Mean :0.9946
## 3rd Qu.: 0.7119398 3rd Qu.:1.0000 3rd Qu.:1.0000 3rd Qu.:1.0000
## Max. : 0.9807853 Max. :2.0000 Max. :2.0000 Max. :2.0000
## match_accuracy_result status
## Min. : 0.00000 Length:49244
## 1st Qu.: 0.00000 Class :character
## Median : 0.00000 Mode :character
## Mean : 0.03784
## 3rd Qu.: 0.00000
## Max. :22.31002
## UserID Timestamp Academic_level Gender
## Min. : 1.00 Length:12 Length:12 Length:12
## 1st Qu.: 3.75 Class :character Class :character Class :character
## Median : 6.50 Mode :character Mode :character Mode :character
## Mean : 6.50
## 3rd Qu.: 9.25
## Max. :12.00
## Age_group Exp_ARVR Globe_usage_frequency
## Length:12 Length:12 Length:12
## Class :character Class :character Class :character
## Mode :character Mode :character Mode :character
##
##
##
## Have_used_VisionPro
## Length:12
## Class :character
## Mode :character
##
##
##
## UserID Timestamp Mentally_demanding Physically_demanding
## Min. : 1.00 Length:12 Length:12 Length:12
## 1st Qu.: 3.75 Class :character Class :character Class :character
## Median : 6.50 Mode :character Mode :character Mode :character
## Mean : 6.50
## 3rd Qu.: 9.25
## Max. :12.00
## UserID Timestamp Mentally_demanding Physically_demanding
## Min. : 1.00 Length:12 Length:12 Length:12
## 1st Qu.: 3.75 Class :character Class :character Class :character
## Median : 6.50 Mode :character Mode :character Mode :character
## Mean : 6.50
## 3rd Qu.: 9.25
## Max. :12.00
## UserID Timestamp Positioning_preference Positioning_feedback
## Min. : 1.00 Length:12 Length:12 Length:12
## 1st Qu.: 3.75 Class :character Class :character Class :character
## Median : 6.50 Mode :character Mode :character Mode :character
## Mean : 6.50
## 3rd Qu.: 9.25
## Max. :12.00
## UserID Timestamp Mentally_demanding Physically_demanding
## Min. : 1.00 Length:12 Length:12 Length:12
## 1st Qu.: 3.75 Class :character Class :character Class :character
## Median : 6.50 Mode :character Mode :character Mode :character
## Mean : 6.50
## 3rd Qu.: 9.25
## Max. :12.00
## UserID Timestamp Mentally_demanding Physically_demanding
## Min. : 1.00 Length:12 Length:12 Length:12
## 1st Qu.: 3.75 Class :character Class :character Class :character
## Median : 6.50 Mode :character Mode :character Mode :character
## Mean : 6.50
## 3rd Qu.: 9.25
## Max. :12.00
## UserID Timestamp Rotation_preference Rotation_feedback
## Min. : 1.00 Length:12 Length:12 Length:12
## 1st Qu.: 3.75 Class :character Class :character Class :character
## Median : 6.50 Mode :character Mode :character Mode :character
## Mean : 6.50
## 3rd Qu.: 9.25
## Max. :12.00
## UserID Timestamp Mentally_demanding Physically_demanding
## Min. : 1.00 Length:12 Length:12 Length:12
## 1st Qu.: 3.75 Class :character Class :character Class :character
## Median : 6.50 Mode :character Mode :character Mode :character
## Mean : 6.50
## 3rd Qu.: 9.25
## Max. :12.00
## UserID Timestamp Mentally_demanding Physically_demanding
## Min. : 1.00 Length:12 Length:12 Length:12
## 1st Qu.: 3.75 Class :character Class :character Class :character
## Median : 6.50 Mode :character Mode :character Mode :character
## Mean : 6.50
## 3rd Qu.: 9.25
## Max. :12.00
## UserID Timestamp Scale_preference Scale_feedback
## Min. : 1.00 Length:12 Length:12 Length:12
## 1st Qu.: 3.75 Class :character Class :character Class :character
## Median : 6.50 Mode :character Mode :character Mode :character
## Mean : 6.50
## 3rd Qu.: 9.25
## Max. :12.00
## UserID Timestamp Combined_positioning_preference
## Min. : 1.00 Length:12 Length:12
## 1st Qu.: 3.75 Class :character Class :character
## Median : 6.50 Mode :character Mode :character
## Mean : 6.50
## 3rd Qu.: 9.25
## Max. :12.00
## Combined_rotation_preference Combined_scale_preference Combined_feedback
## Length:12 Length:12 Length:12
## Class :character Class :character Class :character
## Mode :character Mode :character Mode :character
##
##
##
Restructure the data for better analysis
# Positioning
data.positioning.accuracy <- data %>%
filter(Type == "positionTask") %>%
select(UserID, TaskID, rotateGlobeWhileDragging, match_accuracy_result, status) %>%
filter(status == "Matched") %>%
select(-status) %>%
mutate(Technique = if_else(rotateGlobeWhileDragging, "rotatingGlobe", "nonRotatingGlobe")) %>%
select(-rotateGlobeWhileDragging) %>%
rename("Accuracy" = "match_accuracy_result")
data.positioning.time <- data %>%
filter(Type == "positionTask") %>%
select(UserID, TaskID, rotateGlobeWhileDragging, Date) %>%
group_by(UserID, TaskID, rotateGlobeWhileDragging) %>%
summarise(
Time = as.numeric(difftime(max(Date), min(Date), units = "mins")),
.groups = "drop"
) %>%
mutate(Technique = if_else(rotateGlobeWhileDragging, "rotatingGlobe", "nonRotatingGlobe")) %>%
select(-rotateGlobeWhileDragging)
data.positioning.borg <- data %>%
filter(Type == "positionTask") %>%
mutate(Technique = if_else(rotateGlobeWhileDragging, "rotatingGlobe", "nonRotatingGlobe")) %>%
select(UserID, Technique) %>%
distinct() %>%
inner_join(positioning_NRG, by = "UserID") %>%
rename(BORG_NRG = Physically_demanding) %>%
select(-Timestamp, -Mentally_demanding) %>%
mutate(BORG_NRG = as.numeric(str_extract(BORG_NRG, "\\d+(\\.\\d+)?"))) %>%
inner_join(positioning_RG, by = "UserID") %>%
rename(BORG_RG = Physically_demanding) %>%
select(-Timestamp, -Mentally_demanding) %>%
mutate(BORG_RG = as.numeric(str_extract(BORG_RG, "\\d+(\\.\\d+)?"))) %>%
mutate(
BORGRPE = if_else(Technique == "rotatingGlobe", BORG_RG, BORG_NRG)
) %>%
select(-BORG_RG, -BORG_NRG)
data.positioning.paas <- data %>%
filter(Type == "positionTask") %>%
mutate(Technique = if_else(rotateGlobeWhileDragging, "rotatingGlobe", "nonRotatingGlobe")) %>%
select(UserID, Technique) %>%
distinct() %>%
inner_join(positioning_NRG, by = "UserID") %>%
rename(PAAS_NRG = Mentally_demanding) %>%
select(-Timestamp, -Physically_demanding) %>%
mutate(PAAS_NRG = as.numeric(str_extract(PAAS_NRG, "\\d+(\\.\\d+)?"))) %>%
inner_join(positioning_RG, by = "UserID") %>%
rename(PAAS_RG = Mentally_demanding) %>%
select(-Timestamp, -Physically_demanding) %>%
mutate(PAAS_RG = as.numeric(str_extract(PAAS_RG, "\\d+(\\.\\d+)?"))) %>%
mutate(
PAAS = if_else(Technique == "rotatingGlobe", PAAS_RG, PAAS_NRG)
) %>%
select(-PAAS_RG, -PAAS_NRG)
data.positioning.qualitative <- positioning_preference %>%
select(-Timestamp) %>%
mutate(
Positioning_preference = case_when(
str_detect(Positioning_preference, "Static orientation") ~ "staticOrientation",
str_detect(Positioning_preference, "Adaptive orientation") ~ "adaptiveOrientation",
str_detect(Positioning_preference, "no preference") ~ "noPreference",
TRUE ~ "unknown"
),
Positioning_preference = as.factor(Positioning_preference)
)
# Rotating
data.rotating.accuracy <- data %>%
filter(Type == "rotationTask") %>%
select(UserID, TaskID, oneHandedRotationGesture, match_accuracy_result, status) %>%
filter(status == "Matched") %>%
select(-status) %>%
mutate(Technique = if_else(oneHandedRotationGesture, "oneHanded", "twoHanded")) %>%
select(-oneHandedRotationGesture) %>%
rename("Accuracy" = "match_accuracy_result")
data.rotating.time <- data %>%
filter(Type == "rotationTask") %>%
select(UserID, TaskID, oneHandedRotationGesture, Date) %>%
group_by(UserID, TaskID, oneHandedRotationGesture) %>%
summarise(
Time = as.numeric(difftime(max(Date), min(Date), units = "mins")),
.groups = "drop"
) %>%
mutate(Technique = if_else(oneHandedRotationGesture, "oneHanded", "twoHanded")) %>%
select(-oneHandedRotationGesture)
data.rotating.borg <- data %>%
filter(Type == "rotationTask") %>%
mutate(Technique = if_else(oneHandedRotationGesture, "oneHanded", "twoHanded")) %>%
select(UserID, Technique) %>%
distinct() %>%
inner_join(rotation_OH, by = "UserID") %>%
rename(BORG_OH = Physically_demanding) %>%
select(-Timestamp, -Mentally_demanding) %>%
mutate(BORG_OH = as.numeric(str_extract(BORG_OH, "\\d+(\\.\\d+)?"))) %>%
inner_join(rotation_TH, by = "UserID") %>%
rename(BORG_TH = Physically_demanding) %>%
select(-Timestamp, -Mentally_demanding) %>%
mutate(BORG_TH = as.numeric(str_extract(BORG_TH, "\\d+(\\.\\d+)?"))) %>%
mutate(
BORGRPE = if_else(Technique == "oneHanded", BORG_OH, BORG_TH)
) %>%
select(-BORG_OH, -BORG_TH)
data.rotating.paas <- data %>%
filter(Type == "rotationTask") %>%
mutate(Technique = if_else(oneHandedRotationGesture, "oneHanded", "twoHanded")) %>%
select(UserID, Technique) %>%
distinct() %>%
inner_join(rotation_OH, by = "UserID") %>%
rename(PAAS_OH = Mentally_demanding) %>%
select(-Timestamp, -Physically_demanding) %>%
mutate(PAAS_OH = as.numeric(str_extract(PAAS_OH, "\\d+(\\.\\d+)?"))) %>%
inner_join(rotation_TH, by = "UserID") %>%
rename(PAAS_TH = Mentally_demanding) %>%
select(-Timestamp, -Physically_demanding) %>%
mutate(PAAS_TH = as.numeric(str_extract(PAAS_TH, "\\d+(\\.\\d+)?"))) %>%
mutate(
PAAS = if_else(Technique == "oneHanded", PAAS_OH, PAAS_TH)
) %>%
select(-PAAS_OH, -PAAS_TH)
data.rotating.qualitative <- rotation_preference %>%
select(-Timestamp) %>%
mutate(
Rotation_preference = case_when(
str_detect(Rotation_preference, "One-handed") ~ "oneHandedPreference",
str_detect(Rotation_preference, "Two-handed") ~ "twoHandedPreference",
str_detect(Rotation_preference, "no preference") ~ "noPreference",
TRUE ~ "unknown"
),
Rotation_preference = as.factor(Rotation_preference)
)
# Scale
data.scale.accuracy <- data %>%
filter(Type == "scaleTask") %>%
select(UserID, TaskID, moveGlobeWhileScaling, match_accuracy_result, status) %>%
filter(status == "Matched") %>%
select(-status) %>%
mutate(Technique = if_else(moveGlobeWhileScaling, "movingGlobe", " nonMovingGlobe")) %>%
select(-moveGlobeWhileScaling) %>%
rename("Accuracy" = "match_accuracy_result")
data.scale.time <- data %>%
filter(Type == "scaleTask") %>%
select(UserID, TaskID, moveGlobeWhileScaling, Date) %>%
group_by(UserID, TaskID, moveGlobeWhileScaling) %>%
summarise(
Time = as.numeric(difftime(max(Date), min(Date), units = "mins")),
.groups = "drop"
) %>%
mutate(Technique = if_else(moveGlobeWhileScaling, "movingGlobe", "nonMovingGLobe")) %>%
select(-moveGlobeWhileScaling)
data.scale.borg <- data %>%
filter(Type == "scaleTask") %>%
mutate(Technique = if_else(moveGlobeWhileScaling, "movingGlobe", "nonMovingGlobe")) %>%
select(UserID, Technique) %>%
distinct() %>%
inner_join(scale_NMG, by = "UserID") %>%
rename(BORG_NMG = Physically_demanding) %>%
select(-Timestamp, -Mentally_demanding) %>%
mutate(BORG_NMG = as.numeric(str_extract(BORG_NMG, "\\d+(\\.\\d+)?"))) %>%
inner_join(scale_MG, by = "UserID") %>%
rename(BORG_MG = Physically_demanding) %>%
select(-Timestamp, -Mentally_demanding) %>%
mutate(BORG_MG = as.numeric(str_extract(BORG_MG, "\\d+(\\.\\d+)?"))) %>%
mutate(
BORGRPE = if_else(Technique == "movingGlobe", BORG_MG, BORG_NMG)
) %>%
select(-BORG_MG, -BORG_NMG)
data.scale.paas <- data %>%
filter(Type == "scaleTask") %>%
mutate(Technique = if_else(moveGlobeWhileScaling, "movingGlobe", "nonMovingGlobe")) %>%
select(UserID, Technique) %>%
distinct() %>%
inner_join(scale_NMG, by = "UserID") %>%
rename(PAAS_NMG = Mentally_demanding) %>%
select(-Timestamp, -Physically_demanding) %>%
mutate(PAAS_NMG = as.numeric(str_extract(PAAS_NMG, "\\d+(\\.\\d+)?"))) %>%
inner_join(scale_MG, by = "UserID") %>%
rename(PAAS_MG = Mentally_demanding) %>%
select(-Timestamp, -Physically_demanding) %>%
mutate(PAAS_MG = as.numeric(str_extract(PAAS_MG, "\\d+(\\.\\d+)?"))) %>%
mutate(
PAAS = if_else(Technique == "movingGlobe", PAAS_MG, PAAS_NMG)
) %>%
select(-PAAS_MG, -PAAS_NMG)
data.scale.qualitative <- scale_preference %>%
select(-Timestamp) %>%
mutate(
Scale_preference = case_when(
str_detect(Scale_preference, "Maintain distance") ~ "maintainDistance",
str_detect(Scale_preference, "Maintain globe") ~ "maintainGlobe",
str_detect(Scale_preference, "no preference") ~ "noPreference",
TRUE ~ "unknown"
),
Scale_preference = as.factor(Scale_preference)
)
# Combined qualitative
data.combined.qualitative <- combined_preference %>%
select(-Timestamp) %>%
rename(
Positioning_preference = Combined_positioning_preference,
Rotation_preference = Combined_rotation_preference,
Scale_preference = Combined_scale_preference
) %>%
mutate(
Positioning_preference = case_when(
str_detect(Positioning_preference, "Static orientation") ~ "staticOrientation",
str_detect(Positioning_preference, "Adaptive orientation") ~ "adaptiveOrientation",
str_detect(Positioning_preference, "No preference") ~ "noPreference",
TRUE ~ "unknown"
),
Positioning_preference = as.factor(Positioning_preference)
) %>%
mutate(
Rotation_preference = case_when(
str_detect(Rotation_preference, "One-handed") ~ "oneHandedPreference",
str_detect(Rotation_preference, "Two-handed") ~ "twoHandedPreference",
str_detect(Rotation_preference, "No preference") ~ "noPreference",
TRUE ~ "unknown"
),
Rotation_preference = as.factor(Rotation_preference)
) %>%
mutate(
Scale_preference = case_when(
str_detect(Scale_preference, "Maintain distance") ~ "maintainDistance",
str_detect(Scale_preference, "Maintain globe") ~ "maintainGlobe",
str_detect(Scale_preference, "No preference") ~ "noPreference",
TRUE ~ "unknown"
),
Scale_preference = as.factor(Scale_preference)
)## [1] 12
# Participants' gender distribution
demographic.gender <- demographic %>%
select(UserID, Gender) %>%
distinct() %>%
group_by(Gender) %>%
summarise(count = n()) %>%
mutate(percentage = round(count / sum(count) * 100, 1), percentage = paste0(percentage, "%"))
demographic.gender## # A tibble: 2 × 3
## Gender count percentage
## <chr> <int> <chr>
## 1 Man 10 83.3%
## 2 Woman 2 16.7%
# Participants' gender distribution chart
ggplot(demographic.gender, aes(x = "", y = count, fill = Gender)) +
geom_col(width = 1, color = "white") +
coord_polar(theta = "y") +
geom_text(aes(label = percentage), position = position_stack(vjust = 0.5), size = 4) +
labs(title = "Distribution of Participants' Gender") +
theme_void()# Participants' academic level distribution
demographic.academic_level <- demographic %>%
select(UserID, Academic_level) %>%
distinct() %>%
group_by(Academic_level) %>%
summarise(count = n()) %>%
mutate(percentage = round(count / sum(count) * 100, 1), graph_label = paste0(percentage, "%")) %>%
rename(`Academic levels` = Academic_level)
demographic.academic_level## # A tibble: 3 × 4
## `Academic levels` count percentage graph_label
## <chr> <int> <dbl> <chr>
## 1 Graduate Student 10 83.3 83.3%
## 2 Postdoctoral Researcher 1 8.3 8.3%
## 3 Undergraduate Student 1 8.3 8.3%
# Participants' academic level distribution chart
ggplot(demographic.academic_level, aes(x = "", y = count, fill = `Academic levels`)) +
geom_col(width = 1, color = "white") +
coord_polar(theta = "y") +
geom_text(aes(label = graph_label), position = position_stack(vjust = 0.5), size = 4) +
labs(title = "Distribution of Participants' Academic Level") +
theme_void() # Participants' previous AR/VR experience distribution
demographic.ARVR_exp <- demographic %>%
select(UserID, Exp_ARVR ) %>%
distinct() %>%
group_by(Exp_ARVR) %>%
summarise(count = n()) %>%
mutate(percentage = round(count / sum(count) * 100, 1),
label = paste0(percentage, "%"),
ShortLabel = fct_recode(Exp_ARVR,
"No experience" = "I have no experience")
) %>%
rename(`Previous AR/VR experience` = ShortLabel)
demographic.ARVR_exp## # A tibble: 3 × 5
## Exp_ARVR count percentage label Previous AR/VR exper…¹
## <chr> <int> <dbl> <chr> <fct>
## 1 Beginner (less than 5 hours exp… 4 33.3 33.3% Beginner (less than 5…
## 2 Familiar (5-20 hours experience) 3 25 25% Familiar (5-20 hours …
## 3 I have no experience 5 41.7 41.7% No experience
## # ℹ abbreviated name: ¹`Previous AR/VR experience`
# Participants' previous AR/VR experience distribution chart
ggplot(demographic.ARVR_exp, aes(x = "", y = count, fill = `Previous AR/VR experience`)) +
geom_col(width = 1, color = "white") +
coord_polar(theta = "y") +
geom_text(aes(label = label), position = position_stack(vjust = 0.5), size = 4) +
labs(title = "Distribution of Participants Previous AR/VR Experience") +
theme_void() # Participants' previous globe experience distribution
demographic.globes_exp <- demographic %>%
select(UserID, Globe_usage_frequency) %>%
distinct() %>%
group_by(Globe_usage_frequency) %>%
summarise(count = n()) %>%
mutate(percentage = round(count / sum(count) * 100, 1),
graph_label = paste0(percentage, "%")) %>%
rename(`Previous globes experience` = Globe_usage_frequency)
demographic.globes_exp## # A tibble: 3 × 4
## `Previous globes experience` count percentage graph_label
## <chr> <int> <dbl> <chr>
## 1 A few times a month 1 8.3 8.3%
## 2 A few times a year 3 25 25%
## 3 Once every few years 8 66.7 66.7%
# Participants' previous globe experience distribution chart
ggplot(demographic.globes_exp, aes(x = "", y = count, fill = `Previous globes experience`)) +
geom_col(width = 1, color = "white") +
coord_polar(theta = "y") +
geom_text(aes(label = graph_label), position = position_stack(vjust = 0.5), size = 4) +
labs(title = "Distribution of Participants Previous Globe Experience") +
theme_void() # Participants' previous Apple Vision Pro Experience distribution
demographic.visionpro_exp <- demographic %>%
select(UserID, Have_used_VisionPro) %>%
distinct() %>%
group_by(Have_used_VisionPro) %>%
summarise(count = n()) %>%
mutate(
percentage = round(count / sum(count) * 100, 1),
graph_label = paste0(percentage, "%")
) %>%
rename(`Have used Apple Vision Pro` = Have_used_VisionPro)
demographic.visionpro_exp## # A tibble: 2 × 4
## `Have used Apple Vision Pro` count percentage graph_label
## <chr> <int> <dbl> <chr>
## 1 I have never used the Apple Vision Pro 11 91.7 91.7%
## 2 I have used the Apple Vision Pro once or twice 1 8.3 8.3%
# Participants' previous Apple Vision Pro Experience distribution chart
ggplot(demographic.visionpro_exp, aes(x = "", y = count, fill = `Have used Apple Vision Pro`)) +
geom_col(width = 1, color = "white") +
coord_polar(theta = "y") +
geom_text(aes(label = graph_label), position = position_stack(vjust = 0.5), size = 4) +
labs(title = "Distribution of Participants Previous AR/VR Experience") +
theme_void() data.positioning <- data %>%
mutate(positionCondition = if_else(rotateGlobeWhileDragging, "rotatingGlobe", "nonRotatingGlobe")) %>%
select(-rotateGlobeWhileDragging) %>%
inner_join(demographic, by = "UserID") %>%
inner_join(positioning_NRG, by = "UserID") %>%
rename(
PAAS_NRG = Mentally_demanding,
BORG_NRG = Physically_demanding
) %>%
mutate(
PAAS_NRG = as.numeric(str_extract(PAAS_NRG, "\\d+(\\.\\d+)?")),
BORG_NRG = as.numeric(str_extract(BORG_NRG, "\\d+(\\.\\d+)?"))
) %>%
mutate(
PAAS_NRG = if_else(positionCondition == "nonRotatingGlobe", PAAS_NRG, NA_real_),
BORG_NRG = if_else(positionCondition == "nonRotatingGlobe", BORG_NRG, NA_real_)
) %>%
inner_join(positioning_RG, by = "UserID") %>%
rename(
PAAS_RG = Mentally_demanding,
BORG_RG = Physically_demanding
) %>%
mutate(
PAAS_RG = as.numeric(str_extract(PAAS_RG, "\\d+(\\.\\d+)?")),
BORG_RG = as.numeric(str_extract(BORG_RG, "\\d+(\\.\\d+)?"))
) %>%
mutate(
PAAS_RG = if_else(positionCondition == "rotatingGlobe", PAAS_RG, NA_real_),
BORG_RG = if_else(positionCondition == "rotatingGlobe", BORG_RG, NA_real_)
) %>%
inner_join(positioning_preference, by = "UserID") %>%
rename(
technique_preference = Positioning_preference,
technique_feedback = Positioning_feedback
) %>%
mutate(
technique_preference = case_when(
str_detect(technique_preference, "Static orientation") ~ "staticOrientation",
str_detect(technique_preference, "Adaptive orientation") ~ "adaptiveOrientation",
str_detect(technique_preference, "no preference") ~ "noPreference",
TRUE ~ "unknown"
) ) %>%
filter(Type == "positionTask") %>%
select(UserID, TaskID, ActionID, positionCondition, distance, direction, Date, ActionStatus, main_translation_x,
main_translation_y, main_translation_z, target_translation_x, target_translation_y, target_translation_z,
match_accuracy_result, status, PAAS_NRG, BORG_NRG, PAAS_RG, BORG_RG, technique_preference, technique_feedback) %>%
mutate(distance = as.factor(distance),
direction = as.factor(direction),
positionCondition = as.factor(positionCondition),
status = as.factor(status),
technique_preference = as.factor(technique_preference))##
## Shapiro-Wilk normality test
##
## data: data.positioning.accuracy$Accuracy
## W = 0.97029, p-value = 2.086e-09
hist(data.positioning.accuracy$Accuracy, breaks = 100,
main = "Histogram of Positioning Gestures Accuracy", xlab = "Accuracy",
col = "lightblue", xlim = c(0, 0.06))plot(density(data.positioning.accuracy$Accuracy),
main = "Density Plot of Positioning Gestures Accuracy", xlab = "Accuracy",
col = "blue", lwd = 2, xlim = c(0, 0.08))Although the w value is close to 1, the p value is below 0.05 so we reject null hypothesis that the data is normally distributed So, we cannot use one way ANOVA, instead, we use ART ANOVA test
data.positioning.matched <- data.positioning %>%
filter(status == "Matched")
data.positioning.matched.accuracy_avg.long <- data.positioning.matched %>%
group_by(UserID, positionCondition, distance, direction) %>%
summarise(mean_accuracy = mean(match_accuracy_result, na.rm = TRUE), .groups = 'drop')
data.positioning.matched.art <- art(mean_accuracy ~ positionCondition * distance * direction + (1|UserID), data = data.positioning.matched.accuracy_avg.long)
anova(data.positioning.matched.art)## Analysis of Variance of Aligned Rank Transformed Data
##
## Table Type: Analysis of Deviance Table (Type III Wald F tests with Kenward-Roger df)
## Model: Mixed Effects (lmer)
## Response: art(mean_accuracy)
##
## F Df Df.res Pr(>F)
## 1 positionCondition 0.88851 1 99.000 0.3481756
## 2 distance 8.58240 1 99.545 0.0042088 **
## 3 direction 3.51399 2 99.527 0.0335248 *
## 4 positionCondition:distance 0.88433 1 99.000 0.3493079
## 5 positionCondition:direction 0.21943 2 99.000 0.8033694
## 6 distance:direction 0.25114 2 99.512 0.7784052
## 7 positionCondition:distance:direction 1.62425 2 99.000 0.2022653
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# • The main effect of positionCondition was not statistically significant: F(1, 99) = 0.89, p = 0.348.
# • The main effect of distance was statistically significant: F(1, 99.55) = 8.58, p = 0.0042 (**).
# • The main effect of direction was also statistically significant: F(2, 99.53) = 3.51, p = 0.0335 (*).
# • The interaction between positionCondition and distance was not significant: F(1, 99) = 0.88, p = 0.349.
# • The interaction between positionCondition and direction was not significant: F(2, 99) = 0.22, p = 0.803.
# • The interaction between distance and direction was not significant: F(2, 99.51) = 0.25, p = 0.778.
# • The three-way interaction (positionCondition × distance × direction) was not significant: F(2, 99) = 1.62, p = 0.202.
# There were significant main effects of both distance and direction on mean accuracy, indicating that participants’ accuracy was influenced independently by how far the task was and from which direction it came. However, positionCondition had no significant effect, and no interaction terms reached statistical significance. This suggests that the combined effects of position, distance, and direction do not differentially impact accuracy beyond the main effects of distance and direction alone.
# Plotting for position techniques
data.positioning.matched.accuracy_avg.long %>%
group_by(positionCondition) %>%
summarise(
mean_mean_accuracy = mean(mean_accuracy, na.rm = TRUE),
se = sd(mean_accuracy, na.rm = TRUE) / sqrt(n()),
ci = qt(0.975, df = n() - 1) * se,
.groups = "drop"
) %>%
mutate(positionCondition = case_when(
positionCondition == "rotatingGlobe" ~ "Adaptive Orientation",
positionCondition == "nonRotatingGlobe" ~ "Static Orientation",
TRUE ~ as.character(positionCondition))) %>%
ggplot(aes(x = positionCondition, y = mean_mean_accuracy, fill = positionCondition)) +
geom_col(width = 0.6) +
geom_errorbar(aes(ymin = mean_mean_accuracy - ci, ymax = mean_mean_accuracy + ci), width = 0.2) +
labs(
title = "Mean Match Accuracy by Positioning Technique",
x = "Positioning Technique",
y = "Mean Accuracy",
fill = "Positioning Technique"
) +
scale_fill_manual(
values = c("Adaptive Orientation" = "#a6bddb",
"Static Orientation" = "#d0d1e6")
) +
theme_minimal() +
theme(axis.text.x = element_text()) # Plotting for distance conditions
data.positioning.matched.accuracy_avg.long %>%
group_by(distance) %>%
summarise(
mean_mean_accuracy = mean(mean_accuracy, na.rm = TRUE),
se = sd(mean_accuracy, na.rm = TRUE) / sqrt(n()),
ci = qt(0.975, df = n() - 1) * se,
.groups = "drop"
) %>%
ggplot(aes(x = distance, y = mean_mean_accuracy, fill = distance)) +
geom_col(width = 0.6) +
geom_errorbar(aes(ymin = mean_mean_accuracy - ci, ymax = mean_mean_accuracy + ci), width = 0.2) +
labs(
title = "Mean Match Accuracy by Globe Separation Distance",
x = "Globe Distance",
y = "Mean Accuracy",
fill = "Globe Distance"
) +
scale_fill_manual(
values = c(near = "#a6bddb",
far = "#d0d1e6")
) +
theme_minimal() +
theme(axis.text.x = element_text())# Plotting for direction conditions
data.positioning.matched.accuracy_avg.long %>%
group_by(direction) %>%
summarise(
mean_mean_accuracy = mean(mean_accuracy, na.rm = TRUE),
se = sd(mean_accuracy, na.rm = TRUE) / sqrt(n()),
ci = qt(0.975, df = n() - 1) * se,
.groups = "drop"
) %>%
ggplot(aes(x = direction, y = mean_mean_accuracy, fill = direction)) +
geom_col(width = 0.6) +
geom_errorbar(aes(ymin = mean_mean_accuracy - ci, ymax = mean_mean_accuracy + ci), width = 0.2) +
labs(
title = "Mean Match Accuracy by Globe Separation Direction",
x = "Globe Direction",
y = "Mean Accuracy",
fill = "Globe Direction"
) +
scale_fill_manual(
values = c(diagonal = "#a6bddb",
horizontal = "#d0d1e6",
vertical = "#b8e0d2")
) +
theme_minimal() +
theme(axis.text.x = element_text())# Plotting for both Position Conditions and Technique
data.positioning.matched.accuracy_avg.long %>%
group_by(positionCondition, distance, direction) %>%
summarise(
mean_mean_accuracy = mean(mean_accuracy, na.rm = TRUE),
se = sd(mean_accuracy, na.rm = TRUE) / sqrt(n()),
ci = qt(0.975, df = n() - 1) * se,
.groups = "drop"
) %>%
mutate(positionCondition = case_when(
positionCondition == "rotatingGlobe" ~ "Adaptive orientation",
positionCondition == "nonRotatingGlobe" ~ "Static orientation",
TRUE ~ as.character(positionCondition))) %>%
ggplot(aes(x = positionCondition, y = mean_mean_accuracy, fill = positionCondition)) +
geom_col(width = 0.6) +
geom_errorbar(aes(ymin = mean_mean_accuracy - ci, ymax = mean_mean_accuracy + ci),
width = 0.2) +
facet_wrap(~ distance + direction) +
labs(
title = "Mean Match Accuracy by Positioning Technique, Distance, and Direction",
x = "Positioning technique",
y = "Mean accuracy",
fill = "Positioning technique"
) +
scale_fill_manual(
values = c("Adaptive orientation" = "#a6bddb",
"Static orientation" = "#d0d1e6")
) +
theme_minimal() +
theme(axis.text.x = element_blank())# Boxplots for globe technique and conditions
data.positioning.matched.accuracy_avg.long %>%
mutate(positionCondition = case_when(
positionCondition == "rotatingGlobe" ~ "Adaptive\norientation",
positionCondition == "nonRotatingGlobe" ~ "Static\norientation",
TRUE ~ as.character(positionCondition))) %>%
ggplot(aes(x = positionCondition, y = mean_accuracy)) +
geom_boxplot(outlier.shape = NA, fill = "lightblue") +
geom_jitter(width = 0.1, size = 2, alpha = 0.7) +
facet_wrap(~ distance + direction) +
labs(title = "Boxplots of Accuracy by\nPositioning Technique, Distance and Direction",
x = "Positioning technique",
y = "Match accuracy") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5)
)data.positioning.matched.accuracy_avg.long %>%
group_by(distance) %>%
summarise(mean_accuracy = mean(mean_accuracy)) %>%
pivot_wider(names_from = distance, values_from = mean_accuracy) %>%
mutate(percent_diff = ((far - near) / near) * 100)## # A tibble: 1 × 3
## far near percent_diff
## <dbl> <dbl> <dbl>
## 1 0.0256 0.0227 12.7
data.positioning.matched.accuracy_avg.long %>%
group_by(direction) %>%
summarise(mean_accuracy = mean(mean_accuracy)) %>%
arrange(desc(mean_accuracy)) %>%
mutate(percent_diff_from_lowest = (mean_accuracy - min(mean_accuracy)) / min(mean_accuracy) * 100)## # A tibble: 3 × 3
## direction mean_accuracy percent_diff_from_lowest
## <fct> <dbl> <dbl>
## 1 horizontal 0.0252 13.5
## 2 diagonal 0.0250 12.5
## 3 vertical 0.0222 0
##
## Shapiro-Wilk normality test
##
## data: data.positioning.time$Time
## W = 0.59479, p-value < 2.2e-16
hist(data.positioning.time$Time, breaks = 100,
main = "Histogram of Positioning Gestures Task Completion Time", xlab = "Completion Time",
col = "lightblue", xlim = c(0, 1))plot(density(data.positioning.time$Time),
main = "Density Plot of Positioning Gestures Task Completion Time", xlab = "Completion Time",
col = "blue", lwd = 2, xlim = c(0, 1))data.positioning.taskCompletion_avg.long <- data.positioning %>%
group_by(UserID, positionCondition, TaskID, distance, direction) %>%
summarise(
completion_time = as.numeric(difftime(max(Date), min(Date), units = "mins")),
.groups = "drop"
) %>%
group_by(UserID, positionCondition, distance, direction) %>%
summarise(
avg_completion_time = mean(completion_time),
.groups = "drop"
)
data.positioning.taskCompletion_avg.art <- art(avg_completion_time ~ positionCondition * distance * direction + (1|UserID), data = data.positioning.taskCompletion_avg.long)
anova(data.positioning.taskCompletion_avg.art)## Analysis of Variance of Aligned Rank Transformed Data
##
## Table Type: Analysis of Deviance Table (Type III Wald F tests with Kenward-Roger df)
## Model: Mixed Effects (lmer)
## Response: art(avg_completion_time)
##
## F Df Df.res Pr(>F)
## 1 positionCondition 0.61363 1 99.002 0.4352944
## 2 distance 1.75116 1 100.619 0.1887297
## 3 direction 6.38814 2 100.863 0.0024424 **
## 4 positionCondition:distance 0.24125 1 99.002 0.6243926
## 5 positionCondition:direction 0.50478 2 99.002 0.6051833
## 6 distance:direction 0.57384 2 100.707 0.5651868
## 7 positionCondition:distance:direction 0.43726 2 99.002 0.6470467
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
# • positionCondition had no significant effect on average task completion time:F(1, 99.00) = 0.61, p = 0.435
# • distance also showed no significant effect:F(1, 100.62) = 1.75, p = 0.189
# • direction showed a statistically significant main effect:F(2, 100.86) = 6.39, p = 0.0024 (**), suggesting direction influences how long tasks take
# • The interaction between positionCondition and distance was not significant:F(1, 99.00) = 0.24, p = 0.624
# • The interaction between positionCondition and direction was not significant:F(2, 99.00) = 0.50, p = 0.605
# • The interaction between distance and direction was not significant:F(2, 100.71) = 0.57, p = 0.565
# • The three-way interaction (positionCondition × distance × direction) was also not significant:F(2, 99.00) = 0.44, p = 0.647
#
# Only direction had a statistically significant effect on average task completion time, indicating that the direction from which the task was approached meaningfully influenced how long participants took to complete it. Other factors—positionCondition, distance, and all interaction terms—did not have significant effects. This suggests that regardless of position or distance, direction alone may account for differences in task completion time in this context.
# Plotting for positioning technique
data.positioning.taskCompletion_avg.long %>%
group_by(positionCondition) %>%
summarise(
mean_mean_time = mean(avg_completion_time, na.rm = TRUE),
se = sd(avg_completion_time, na.rm = TRUE) / sqrt(n()),
ci = qt(0.975, df = n() - 1) * se,
.groups = "drop"
) %>%
mutate(positionCondition = case_when(
positionCondition == "rotatingGlobe" ~ "Adaptive Orientation",
positionCondition == "nonRotatingGlobe" ~ "Static Orientation",
TRUE ~ as.character(positionCondition))) %>%
ggplot(aes(x = positionCondition, y = mean_mean_time, fill = positionCondition)) +
geom_col(width = 0.6) +
geom_errorbar(aes(ymin = mean_mean_time - ci, ymax = mean_mean_time + ci), width = 0.2) +
labs(
title = "Average Task Completion Time by Positioning Technique",
x = "Positioning Technique",
y = "Average Completion Time",
fill = "Positioning Technique"
) +
scale_fill_manual(
values = c("Adaptive Orientation" = "#a6bddb",
"Static Orientation" = "#d0d1e6")
) +
theme_minimal() +
theme(axis.text.x = element_blank())# Plotting for distance factors
data.positioning.taskCompletion_avg.long %>%
group_by(distance) %>%
summarise(
mean_mean_time = mean(avg_completion_time, na.rm = TRUE),
se = sd(avg_completion_time, na.rm = TRUE) / sqrt(n()),
ci = qt(0.975, df = n() - 1) * se,
.groups = "drop"
) %>%
ggplot(aes(x = distance, y = mean_mean_time, fill = distance)) +
geom_col(width = 0.6) +
geom_errorbar(aes(ymin = mean_mean_time - ci, ymax = mean_mean_time + ci), width = 0.2) +
labs(
title = "Average Task Completion Time by Globe Distance Factors",
x = "Globe Distance",
y = "Average Completion Time",
fill = "Globe Distance"
) +
scale_fill_manual(
values = c(near= "#a6bddb",
far = "#d0d1e6")
) +
theme_minimal() +
theme(axis.text.x = element_blank())# Plotting for direction factors
data.positioning.taskCompletion_avg.long %>%
group_by(direction) %>%
summarise(
mean_mean_time = mean(avg_completion_time, na.rm = TRUE),
se = sd(avg_completion_time, na.rm = TRUE) / sqrt(n()),
ci = qt(0.975, df = n() - 1) * se,
.groups = "drop"
) %>%
ggplot(aes(x = direction, y = mean_mean_time, fill = direction)) +
geom_col(width = 0.6) +
geom_errorbar(aes(ymin = mean_mean_time - ci, ymax = mean_mean_time + ci), width = 0.2) +
labs(
title = "Average Task Completion Time by Globe Direction",
x = "Globe direction",
y = "Average completion time",
fill = "Globe direction"
) +
scale_fill_manual(
values = c(diagonal = "#a6bddb",
horizontal = "#d0d1e6",
vertical = "#b8e0d2")
) +
theme_minimal() +
theme(axis.text.x = element_blank(),
plot.title = element_text(hjust = 0.5)) # Plotting for both Position Factors and Technique
data.positioning.taskCompletion_avg.long %>%
group_by(positionCondition, distance, direction) %>%
summarise(
mean_mean_time = mean(avg_completion_time, na.rm = TRUE),
se = sd(avg_completion_time, na.rm = TRUE) / sqrt(n()),
ci = qt(0.975, df = n() - 1) * se,
.groups = "drop"
) %>%
mutate(positionCondition = case_when(
positionCondition == "rotatingGlobe" ~ "Adaptive Orientation",
positionCondition == "nonRotatingGlobe" ~ "Static Orientation",
TRUE ~ as.character(positionCondition))) %>%
ggplot(aes(x = positionCondition, y = mean_mean_time, fill = positionCondition)) +
geom_col(width = 0.6) +
geom_errorbar(aes(ymin = mean_mean_time - ci, ymax = mean_mean_time + ci),
width = 0.2) +
facet_wrap(~ distance + direction) +
labs(
title = "Average Task Completion time\nby Globe Technique, Distance, and Direction",
x = "Positioning Technique",
y = "Average Completion Time",
fill = "Positioning Technique"
) +
scale_fill_manual(
values = c("Adaptive Orientation" = "#a6bddb",
"Static Orientation" = "#d0d1e6")
) +
theme_minimal() +
theme(
axis.text.x = element_blank(),
plot.title = element_text(hjust = 0.5)
)# Boxplots for Globe technique, Distance, and Direction Factors
data.positioning.taskCompletion_avg.long %>%
mutate(positionCondition = case_when(
positionCondition == "rotatingGlobe" ~ "Adaptive\nOrientation",
positionCondition == "nonRotatingGlobe" ~ "Static\nOrientation",
TRUE ~ as.character(positionCondition))) %>%
ggplot(aes(x = positionCondition, y = avg_completion_time)) +
geom_boxplot(outlier.shape = NA, fill = "lightblue") +
geom_jitter(width = 0.1, size = 2, alpha = 0.7) +
facet_wrap(~ distance + direction, scales = "free_x") +
labs(title = "Boxplots of Average Task Completion Time\nby Technique, Distance, and Direction",
x = "Technique",
y = "Task Completion Time") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5)
)data.positioning.taskCompletion_avg.long %>%
group_by(direction) %>%
summarise(mean_time = mean(avg_completion_time)) %>%
arrange(desc(mean_time)) %>%
mutate(percent_diff_from_lowest = (mean_time - min(mean_time)) / min(mean_time) * 100)## # A tibble: 3 × 3
## direction mean_time percent_diff_from_lowest
## <fct> <dbl> <dbl>
## 1 horizontal 0.152 43.4
## 2 vertical 0.127 20.0
## 3 diagonal 0.106 0
data.positioning.combined_exertion <- data.positioning.paas %>%
full_join(data.positioning.borg, by = c("UserID", "Technique")) %>%
pivot_longer(
cols = c(PAAS, BORGRPE),
names_to = "Measure",
values_to = "Score"
) %>%
mutate(
Measure = case_when(
Measure == "PAAS" & Technique == "rotatingGlobe" ~ "PAAS_RG",
Measure == "PAAS" & Technique == "nonRotatingGlobe" ~ "PAAS_NRG",
Measure == "BORGRPE" & Technique == "rotatingGlobe" ~ "BORG_RG",
Measure == "BORGRPE" & Technique == "nonRotatingGlobe" ~ "BORG_NRG",
TRUE ~ Measure
),
ExertionType = case_when(
str_detect(Measure, "PAAS") ~ "Cognitive load",
str_detect(Measure, "BORG") ~ "Physical exertion",
TRUE ~ "Unknown"
)
) %>%
select(UserID, Technique, Measure, Score, ExertionType) %>%
mutate(
Technique = as.factor(Technique),
ExertionType = as.factor(ExertionType)
)
data.positioning.combined_exertion.art_anova <- art(Score ~ Technique * ExertionType + (1|UserID), data = data.positioning.combined_exertion)
ggplot(data.positioning.combined_exertion, aes(x = Technique, y = Score, fill = ExertionType)) +
geom_boxplot(width = 0.1, position = position_dodge(0.8)) +
labs(
x = "Positioning Technique",
y = "Score",
title = "Boxplots of Exertion Scores by Behavior and Exertion Type"
) +
scale_fill_manual(
values = c("Cognitive load" = "#a6bddb",
"Physical exertion" = "#d0d1e6")
) +
theme_minimal()data.positioning.combined_exertion %>%
group_by(Technique, ExertionType) %>%
summarise(
mean_score = mean(Score),
sd = sd(Score),
n = n(),
ci = qt(0.975, df = n - 1) * sd / sqrt(n),
.groups = "drop"
) %>%
mutate(Technique = case_when(
Technique == "rotatingGlobe" ~ "Adaptive Orientation",
Technique == "nonRotatingGlobe" ~ "Static Orientation",
TRUE ~ as.character(Technique))) %>%
ggplot(aes(x = Technique, y = mean_score, fill = ExertionType)) +
geom_col(position = position_dodge(width = 0.7), width = 0.6) +
geom_errorbar(aes(ymin = mean_score - ci, ymax = mean_score + ci),
position = position_dodge(width = 0.7), width = 0.2) +
labs(
x = "Positioning technique",
y = "Mean score (95% CI)",
fill = "Exertion type",
title = "Mean score by Positioning Technique and Exertion Type"
) +
scale_fill_manual(
values = c("Cognitive load" = "#a6bddb",
"Physical exertion" = "#d0d1e6")
) +
theme_minimal()data.positioning.combined_exertion %>%
filter(ExertionType == "Cognitive load") %>%
group_by(Technique) %>%
summarise(
mean_score = mean(Score),
sd = sd(Score),
n = n(),
ci = qt(0.975, df = n - 1) * sd / sqrt(n),
.groups = "drop"
) %>%
mutate(Technique = case_when(
Technique == "rotatingGlobe" ~ "Adaptive orientation",
Technique == "nonRotatingGlobe" ~ "Static orientation",
TRUE ~ as.character(Technique))) %>%
ggplot(aes(x = Technique, y = mean_score, fill = Technique)) +
geom_col(position = position_dodge(width = 0.7), width = 0.6) +
geom_errorbar(aes(ymin = mean_score - ci, ymax = mean_score + ci),
position = position_dodge(width = 0.7), width = 0.2) +
labs(
x = "Positioning technique",
y = "Mean score (95% CI)",
fill = "Positioning Technique",
title = "Mean PAAS Score by Positioning Technique"
) +
scale_fill_manual(
values = c("Adaptive orientation" = "#a6bddb",
"Static orientation" = "#d0d1e6")
) +
theme_minimal() +
theme(axis.text.x = element_blank(),
plot.title = element_text(hjust = 0.5)) data.positioning.combined_exertion %>%
filter(ExertionType == "Physical exertion") %>%
group_by(Technique) %>%
summarise(
mean_score = mean(Score),
sd = sd(Score),
n = n(),
ci = qt(0.975, df = n - 1) * sd / sqrt(n),
.groups = "drop"
) %>%
mutate(Technique = case_when(
Technique == "rotatingGlobe" ~ "Adaptive orientation",
Technique == "nonRotatingGlobe" ~ "Static orientation",
TRUE ~ as.character(Technique))) %>%
ggplot(aes(x = Technique, y = mean_score, fill = Technique)) +
geom_col(position = position_dodge(width = 0.7), width = 0.6) +
geom_errorbar(aes(ymin = mean_score - ci, ymax = mean_score + ci),
position = position_dodge(width = 0.7), width = 0.2) +
labs(
x = "Positioning technique",
y = "Mean score (95% CI)",
fill = "Positioning Technique",
title = "Mean BORG RPE Score by Positioning Technique"
) +
scale_fill_manual(
values = c("Adaptive orientation" = "#a6bddb",
"Static orientation" = "#d0d1e6")
) +
theme_minimal() +
theme(axis.text.x = element_blank(),
plot.title = element_text(hjust = 0.5)) data.positioning.combined_exertion %>%
group_by(Technique, ExertionType) %>%
summarise(mean_score = mean(Score))## `summarise()` has grouped output by 'Technique'. You can override using the
## `.groups` argument.
## # A tibble: 4 × 3
## # Groups: Technique [2]
## Technique ExertionType mean_score
## <fct> <fct> <dbl>
## 1 nonRotatingGlobe Cognitive load 2.58
## 2 nonRotatingGlobe Physical exertion 1.92
## 3 rotatingGlobe Cognitive load 3.5
## 4 rotatingGlobe Physical exertion 2.54
data.positioning.qualitative %>%
count(Positioning_preference) %>%
mutate(
percent = n / sum(n),
ncount = paste0(n, "\n", percent_format()(percent))
) %>%
mutate(
Preference = case_when(
Positioning_preference == "adaptiveOrientation" ~ "Adaptive Orientation",
Positioning_preference == "staticOrientation" ~ "Static Orientation",
Positioning_preference == "noPreference" ~ "No Preference"
)) %>%
ggplot(aes(x = "", y = n, fill = Preference)) +
geom_col(width = 1, color = "white") +
coord_polar(theta = "y") +
geom_text(aes(label = ncount), position = position_stack(vjust = 0.5), size = 4) +
labs(
title = "Distribution of Positioning technique Preferences",
fill = "Preference"
) +
scale_fill_manual(
values = c("Adaptive Orientation" = "#a6bddb",
"Static Orientation" = "#d0d1e6",
"No Preference" = "#b8e0d2")
) +
theme_void()data.positioning.qualitative %>%
count(Positioning_preference) %>%
mutate(
Preference = case_when(
Positioning_preference == "adaptiveOrientation" ~ "Adaptive orientation",
Positioning_preference == "staticOrientation" ~ "Static orientation",
Positioning_preference == "noPreference" ~ "No preference"
)
) %>%
ggplot(aes(x = n, y = reorder(Preference, n), fill = Preference)) +
geom_col(width = 0.8) +
geom_text(aes(label = n), hjust = -0.9, size = 5) +
labs(
title = "Distribution of Positioning Technique\nPreferences",
x = NULL,
y = NULL,
fill = "Preference"
) +
scale_fill_manual(
values = c(
"Adaptive orientation" = "#a6bddb",
"Static orientation" = "#d0d1e6",
"No preference" = "#b8e0d2"
)
) +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5, size = 20),
legend.position = "none",
plot.margin = margin(10, 30, 10, 10),
axis.text.y = element_text(size = 18),
axis.text.x = element_blank()
) +
xlim(0, NA)
Comments
Summary
Study: Rotating
Rotating Data Preparation
Rotation Task Study
Accuracy
Normality
Although the w value is close to 1, the p value is below 0.05 so we reject null hypothesis that the data is normally distributed So, we cannot use one way ANOVA, instead, we use Wilcoxon signed-rank test
Statistical tests
Completion Time
Normality
Statistical Tests
Subjective Measures
Physical and Mental Exertion
Preference
Comments
Summary
Study: Scale
Scale Data Preparation
Scale Task Study
Accuracy
Normality
Statistical tests
Completion Time
Normality
Statistical Tests
Subjective Measures
Physical and Mental Exertion
Preference
Comments
Summary
Study: Combined Gesture Preference and Feedback